<template>
  <div class="process-editor-container">
    <!-- 顶部工具栏 -->
    <div class="toolbar">
      <div class="left-tools">
        <el-tooltip content="新建" placement="bottom">
          <el-button :icon="Plus" circle @click="createNewDiagram" />
        </el-tooltip>
        <el-tooltip content="自适应屏幕" placement="bottom">
          <el-button :icon="FullScreen" circle @click="zoomToFit" />
        </el-tooltip>
        <el-tooltip content="方法" placement="bottom">
          <el-button :icon="Operation" circle @click="showMethods" />
        </el-tooltip>
        <el-tooltip content="缩小" placement="bottom">
          <el-button :icon="ZoomOut" circle @click="zoomOut" />
        </el-tooltip>
        <el-tooltip content="后退" placement="bottom">
          <el-button :icon="Back" circle @click="undo" />
        </el-tooltip>
        <el-tooltip content="前进" placement="bottom">
          <el-button :icon="Right" circle @click="redo" />
        </el-tooltip>
        <el-tooltip content="加载XML" placement="bottom">
          <el-button :icon="Upload" circle @click="importXML" />
        </el-tooltip>
      </div>
      <!-- <el-select v-model="selectedModel" placeholder="请选择模型" @change="handleModelChange" clearable style="width: 200px;">
          <el-option 
            v-for="model in modelData" 
            :key="model.fileName" 
            :label="model.processName" 
            :value="model.fileName"
          >
            <span>{{ model.processName }}</span>
            <span style="float: right; color: #8492a6; font-size: 13px">
              {{ model.fileName }}
            </span>
          </el-option>
        </el-select> -->
      <div class="right-tools">
        <el-button type="primary" :icon="Document" @click="showXML">查看XML</el-button>
        <el-button type="primary" :icon="Download" @click="downloadXML">下载XML</el-button>
        <el-button type="primary" :icon="Picture" @click="downloadSVG">下载SVG</el-button>
        <el-button type="primary" :icon="Upload" @click="deployModel">部署模型</el-button>
        <!-- <el-button type="primary" :icon="Star" @click="saveAsTemplate">添加为模板</el-button> -->
        <el-button type="primary" :icon="Close" @click="closeEditor">关闭</el-button>
      </div>
    </div>

    <!-- 主要内容区域 -->
    <div class="main-content">
      <div class="bpmn-editor" ref="bpmnEditor"></div>
      <div class="properties-panel" ref="propertiesPanel"></div>
    </div>

    <!-- XML查看对话框 -->
    <el-dialog v-model="xmlDialogVisible" title="XML内容" width="60%">
      <pre class="xml-content">{{ xmlContent }}</pre>
      <template #footer>
        <span class="dialog-footer">
          <el-button @click="xmlDialogVisible = false">关闭</el-button>
          <el-button type="primary" @click="copyXML">复制</el-button>
        </span>
      </template>
    </el-dialog>

    <!-- 方法对话框 -->
    <el-dialog v-model="methodsDialogVisible" title="可用方法" width="50%">
      <el-table :data="availableMethods" style="width: 100%">
        <el-table-column prop="name" label="方法名称" />
        <el-table-column prop="description" label="描述" />
        <el-table-column fixed="right" label="操作" width="120">
          <template #default="scope">
            <el-button type="text" @click="useMethod(scope.row)">使用</el-button>
          </template>
        </el-table-column>
      </el-table>
    </el-dialog>

    <!-- 文件名称输入对话框 -->
    <el-dialog v-model="fileNameDialogVisible" title="输入文件名称" width="30%">
      <el-form :model="fileNameForm" label-width="80px">
        <el-form-item label="文件名称" required>
          <el-input v-model="fileNameForm.name" placeholder="请输入文件名称" />
        </el-form-item>
      </el-form>
      <template #footer>
        <span class="dialog-footer">
          <el-button @click="fileNameDialogVisible = false">取消</el-button>
          <el-button type="primary" @click="handleFileNameConfirm">确认</el-button>
        </span>
      </template>
    </el-dialog>
  </div>
</template>

<script>
import BpmnModeler from 'bpmn-js/lib/Modeler'
import '@bpmn-io/properties-panel/assets/properties-panel.css'
import {
  BpmnPropertiesPanelModule,
  BpmnPropertiesProviderModule,
  CamundaPlatformPropertiesProviderModule
} from 'bpmn-js-properties-panel'
import camundaModdleDescriptor from 'camunda-bpmn-moddle/resources/camunda'
import 'bpmn-js/dist/assets/diagram-js.css'
import 'bpmn-js/dist/assets/bpmn-font/css/bpmn.css'
import { ElMessage } from 'element-plus'
import * as ElementPlusIconsVue from '@element-plus/icons-vue'

export default {
  name: 'ProcessDefinitionEditor',
  components: {
    Plus: ElementPlusIconsVue.Plus,
    FullScreen: ElementPlusIconsVue.FullScreen,
    Operation: ElementPlusIconsVue.Operation,
    ZoomOut: ElementPlusIconsVue.ZoomOut,
    Back: ElementPlusIconsVue.Back,
    Right: ElementPlusIconsVue.Right,
    Upload: ElementPlusIconsVue.Upload,
    Document: ElementPlusIconsVue.Document,
    Download: ElementPlusIconsVue.Download,
    Picture: ElementPlusIconsVue.Picture,
    Star: ElementPlusIconsVue.Star,
    Close: ElementPlusIconsVue.Close
  },
  data() {
    return {
      bpmnEditor: null,
      propertiesPanel: null,
      modeler: null,
      xmlDialogVisible: false,
      methodsDialogVisible: false,
      xmlContent: '',
      availableMethods: [
        { name: '审批流程', description: '创建一个标准的审批流程模板' },
        { name: '会签流程', description: '创建一个多人会签的流程模板' },
        { name: '并行网关', description: '添加并行网关处理分支' }
      ],
      translations: {
        // 基础属性
        'General': '常规',
        'Details': '详情',
        'Documentation': '节点描述',
        'Element documentation' : '描述',
        'Name': '名称',
        'ID': '标识',
        'Description': '描述',
        'Documentation Format': '文档格式',
        'Documentation Text': '文档内容',
        'Version tag' : '版本标签',
        'Executable' : '可执行文件',
        'ID must be unique.' : '标识必须唯一',
        'This maps to the process definition key.' : '这映射到流程定义键',
        'This maps to the process definition name.' : '这映射到流程定义名称',
        'History cleanup' : '历史清理',
        'Time to live' : '存活时间',
        
        
        // 流程相关
        'Process': '流程',
        'Process ID': '流程标识',
        'Process Name': '流程名称',
        'Process Documentation': '流程文档',
        'Process Version': '流程版本',
        'Process Author': '流程作者',
        'Process Category': '流程分类',
        'Process Priority': '流程优先级',
        'Process History Time To Live': '流程历史存活时间',

        // 执行相关
        'Execution': '执行',
        'Asynchronous Continuations': '异步延续',
        'Asynchronous Before': '异步前置',
        'Asynchronous After': '异步后置',
        'Exclusive': '排他',
        'Job Configuration': '作业配置',
        'Job Priority': '作业优先级',
        'Job Retry Time Cycle': '作业重试时间周期',
        'Job Execution': '作业执行',
        'History Time To Live': '历史存活时间',

        // 任务相关
        'Task': '任务',
        'Task Configuration': '任务配置',
        'Assignee': '处理人',
        'Candidate Users': '候选用户',
        'Candidate Groups': '候选组',
        'Due Date': '到期时间',
        'Follow Up Date': '跟进时间',
        'Priority': '优先级',
        'Task Priority': '任务优先级',
        'Multi Instance': '多实例',
        'Multi Instance Type': '多实例类型',
        'Multi Instance Cardinality': '多实例基数',
        'Multi Instance Collection': '多实例集合',
        'Multi Instance Element Variable': '多实例元素变量',
        'Multi Instance Completion Condition': '多实例完成条件',
        'Tasklist' : '任务列表',
        'Startable' : '启动',
        'Candidate starter' : '分配者',
        'Candidate starter groups' : '候选组',
        'Specify more than one group as a comma separated list.' : '指定多个组作为逗号分隔列表',
        'Candidate starter users' : '候选用户',
        'Specify more than one user as a comma separated list.' : '指定多个用户作为逗号分隔列表',
        'External task' : '外部任务',

        'Job execution' : '作业执行',
        'Execution listeners' : '执行监听器',
        'Start: Java class' : '启动: Java类',
        'Event type' : '事件类型',
        'Listener type' : '监听器类型',
        'Java class' : 'Java类',
        'Field injection' : '字段注入',
        'Type' : '类型',
        'Value' : '值',
        'Create' : '创建',

        'Extension properties' : '扩展属性',



        // 表单相关
        'Forms': '表单',
        'Start initiator' : '启动者',
        'Asynchronous continuation' : '异步延续',
        'Before' : '前置',
        'After' : '后置',
        'Form reference' : '表单引用',
        'Binding' : '绑定',
        'Form key' : '表单标识',
        'Form fields': '表单字段',
        'Label' : '标签',
        'Default value' : '默认值',
        'Constraints' : '约束',
        'initiator' : '启动者',
        'Asynchronous continuation' : '异步延续',
        'Business key' : '业务键',
        'Key' : '键',
        'Form Field': '表单字段',
        'Form Field Type': '表单字段类型',
        'Form Field Label': '表单字段标签',
        'Form Field Default Value': '表单字段默认值',
        'Form Field Validation': '表单字段验证',
        'Form Field Properties': '表单字段属性',
        'Form Field Required': '表单字段必填',
        'Form Field Readonly': '表单字段只读',
        'Form Field Pattern': '表单字段格式',
        'Form Field Min': '表单字段最小值',
        'Form Field Max': '表单字段最大值',

        // 监听器相关
        'Listeners': '监听器',
        'Execution Listener': '执行监听器',
        'Task Listener': '任务监听器',
        'Listener Type': '监听器类型',
        'Listener Class': '监听器类',
        'Listener Expression': '监听器表达式',
        'Listener Script': '监听器脚本',
        'Listener Script Format': '监听器脚本格式',
        'Listener Script Type': '监听器脚本类型',
        'Listener Event': '监听器事件',
        'Listener Fields': '监听器字段',
        'Listener Field Name': '监听器字段名称',
        'Listener Field Value': '监听器字段值',
        'Listener Field Type': '监听器字段类型',

        // 服务任务相关
        'Service': '服务',
        'Service Task': '服务任务',
        'Class': '类',
        'Expression': '表达式',
        'Delegate Expression': '代理表达式',
        'External Task Configuration': '外部任务配置',
        'Topic': '主题',
        'Task Priority': '任务优先级',
        'Service Implementation': '服务实现',
        'Service Implementation Type': '服务实现类型',
        'Service Implementation Class': '服务实现类',
        'Service Implementation Expression': '服务实现表达式',
        'Service Implementation Delegate Expression': '服务实现代理表达式',

        'User assignment' : '用户分配',
        'Candidate groups' : '候选组',
        'Candidate users' : '候选用户',
        'Due date' : '到期时间',
        'The due date as an EL expression (e.g. ${someDate}) or an ISO date (e.g. 2015-06-26T09:54:00).' : '到期时间作为EL表达式（例如${someDate}）或ISO日期（例如2015-06-26T09:54:00）',
        'Follow up date' : '跟进时间',
        'The follow up date as an EL expression (e.g. ${someDate}) or an ISO date (e.g. 2015-06-26T09:54:00).' : '跟进时间作为EL表达式（例如${someDate}）或ISO日期（例如2015-06-26T09:54:00）',

        'Task listeners' : '任务监听器',
        'Listener ID' : '监听器ID',

        'Asynchronous continuation' : '异步延续',

        // 网关相关
        'Gateway': '网关',
        'Gateway Direction': '网关方向',
        'Gateway Type': '网关类型',
        'Default Flow': '默认流',
        'Condition': '条件',
        'Condition Expression': '条件表达式',
        'Condition Type': '条件类型',
        'Gateway Order': '网关顺序',
        'Gateway Async Before': '网关异步前置',
        'Gateway Async After': '网关异步后置',
        'Gateway Exclusive': '网关排他',
        

        // 事件相关
        'Event': '事件',
        'Event Type': '事件类型',
        'Event Definition': '事件定义',
        'Event Definition Type': '事件定义类型',
        'Event Definition Properties': '事件定义属性',
        'Timer Event Definition': '定时器事件定义',
        'Timer Date': '定时器日期',
        'Timer Duration': '定时器持续时间',
        'Timer Cycle': '定时器周期',
        'Message Event Definition': '消息事件定义',
        'Message': '消息',
        'Message Name': '消息名称',
        'Message Payload': '消息负载',
        'Message Correlation': '消息关联',
        'Message Subscription': '消息订阅',
        'Signal Event Definition': '信号事件定义',
        'Signal': '信号',
        'Signal Name': '信号名称',
        'Signal Scope': '信号范围',
        'Signal Definition': '信号定义',
        'Error Event Definition': '错误事件定义',
        'Error': '错误',
        'Error Code': '错误代码',
        'Error Message': '错误消息',
        'Error Variable': '错误变量',
        'Escalation Event Definition': '升级事件定义',
        'Escalation': '升级',
        'Escalation Code': '升级代码',
        'Escalation Name': '升级名称',
        'Compensate Event Definition': '补偿事件定义',
        'Compensation': '补偿',
        'Compensation Activity': '补偿活动',
        'Compensation Handler': '补偿处理器',

        // 数据相关
        'Data': '数据',
        'Data Object': '数据对象',
        'Data Store': '数据存储',
        'Data Association': '数据关联',
        'Data Input': '数据输入',
        'Data Output': '数据输出',
        'Data Input Association': '数据输入关联',
        'Data Output Association': '数据输出关联',
        'Data Object Reference': '数据对象引用',
        'Data Store Reference': '数据存储引用',

        // 其他
        'Properties': '属性',
        'Extension Properties': '扩展属性',
        'Element Documentation': '元素文档',
        'Element Template': '元素模板',
        'Implementation': '实现',
        'Startable In Tasklist': '可在任务列表中启动',
        'Version Tag': '版本标签',
        'Category': '分类',
        'Author': '作者',
        'Version': '版本',
        'History Time To Live': '历史存活时间',
        'Is Executable': '可执行',
        'Is Closed': '已关闭',
        'Is Async': '异步',
        'Is Exclusive': '排他',
        'Is For Compensation': '用于补偿',
        'Is Triggered By Event': '由事件触发',
        'Is Interrupting': '中断',
        'Is Parallel': '并行',
        'Is Sequential': '顺序',
        'Is Collection': '集合',
        'Is Sequential': '顺序',
        'Is Collection': '集合',
        'Is Sequential': '顺序',
        'Is Collection': '集合'
      },
      modelData: [],
      selectedModel: '',
      fileNameDialogVisible: false,
      fileNameForm: {
        name: ''
      },
      pendingUpload: null
    }
  },
  computed: {
    Plus() {
      return ElementPlusIconsVue.Plus
    },
    FullScreen() {
      return ElementPlusIconsVue.FullScreen
    },
    Operation() {
      return ElementPlusIconsVue.Operation
    },
    ZoomOut() {
      return ElementPlusIconsVue.ZoomOut
    },
    Back() {
      return ElementPlusIconsVue.Back
    },
    Right() {
      return ElementPlusIconsVue.Right
    },
    Upload() {
      return ElementPlusIconsVue.Upload
    },
    Document() {
      return ElementPlusIconsVue.Document
    },
    Download() {
      return ElementPlusIconsVue.Download
    },
    Picture() {
      return ElementPlusIconsVue.Picture
    },
    Star() {
      return ElementPlusIconsVue.Star
    },
    Close() {
      return ElementPlusIconsVue.Close
    }
  },
  mounted() {
    this.modeler = new BpmnModeler({
      container: this.$refs.bpmnEditor,
      propertiesPanel: {
        parent: this.$refs.propertiesPanel
      },
      additionalModules: [
        BpmnPropertiesPanelModule,
        BpmnPropertiesProviderModule,
        CamundaPlatformPropertiesProviderModule,
        {
          translate: ['value', (template, replacements) => {
            return this.translations[template] || template
          }]
        }
      ],
      moddleExtensions: {
        camunda: camundaModdleDescriptor
      }
    })

    this.createNewDiagram()
  },
  created() {
    this.fetchList()
  },
  methods: {
    initBpmnModeler(xml) {
      try {
        this.modeler.importXML(xml).then(() => {
          // 导入成功后自适应视图
          const canvas = this.modeler.get('canvas')
          canvas.zoom('fit-viewport')
          ElMessage.success('模型加载成功')
        }).catch(err => {
          console.error('模型加载失败:', err)
          ElMessage.error('模型加载失败')
        })
      } catch (err) {
        console.error('模型加载失败:', err)
        ElMessage.error('模型加载失败')
      }
    },
    handleModelChange() {
      if (!this.selectedModel) {
        // 如果清空选择，创建新图
        this.createNewDiagram()
        return
      }
      this.$get('/getProcessFileXml', {
        fileName: this.selectedModel
      }).then(res => {
        if (res.code === 200) {
          this.initBpmnModeler(res.data)
        } else {
          ElMessage.error('获取模型文件失败')
        }
      }).catch(err => {
        console.error('获取模型文件失败:', err)
        ElMessage.error('获取模型文件失败')
      })
    },
    //查询模板
    fetchList() {
      // TODO: 调用接口获取数据
      // this.tableData = await api.getModelList(this.searchForm)
      this.$get('/getAllProcessFiles',{
        name : ''
      }).then(res =>{
        if(res.code === 200){
          this.modelData = res.data
        }else{
          ElMessage.error('获取模型列表失败')
        }
      }).catch(err =>{
        console.log(err)
      })
    },
    createNewDiagram() {
      try {
        this.modeler.createDiagram()
        ElMessage.success('已创建新的流程图')
      } catch (err) {
        ElMessage.error('创建流程图失败')
      }
    },
    zoomToFit() {
      const canvas = this.modeler.get('canvas')
      canvas.zoom('fit-viewport')
    },
    zoomOut() {
      const canvas = this.modeler.get('canvas')
      const zoom = canvas.zoom()
      canvas.zoom(zoom - 0.1)
    },
    undo() {
      const commandStack = this.modeler.get('commandStack')
      commandStack.undo()
    },
    redo() {
      const commandStack = this.modeler.get('commandStack')
      commandStack.redo()
    },
    importXML() {
      try {
        const input = document.createElement('input')
        input.type = 'file'
        input.accept = '.bpmn,.xml'
        input.onchange = async (e) => {
          const file = e.target.files[0]
          const reader = new FileReader()
          reader.onload = async (e) => {
            try {
              await this.modeler.importXML(e.target.result)
              ElMessage.success('导入成功')
            } catch (err) {
              ElMessage.error('导入失败：' + err.message)
            }
          }
          reader.readAsText(file)
        }
        input.click()
      } catch (err) {
        ElMessage.error('导入失败')
      }
    },
    showXML() {
      try {
        this.modeler.saveXML({ format: true }).then(({ xml }) => {
          this.xmlContent = xml
          this.xmlDialogVisible = true
        })
      } catch (err) {
        ElMessage.error('获取XML失败')
      }
    },
    downloadXML() {
      try {
        this.modeler.saveXML({ format: true }).then(({ xml }) => {
          const blob = new Blob([xml], { type: 'application/xml' })
          const url = window.URL.createObjectURL(blob)
          const link = document.createElement('a')
          link.href = url
          link.download = 'process.bpmn'
          link.click()
          window.URL.revokeObjectURL(url)
          ElMessage.success('下载成功')
        })
      } catch (err) {
        ElMessage.error('下载失败')
      }
    },
    downloadSVG() {
      try {
        this.modeler.saveSVG().then(({ svg }) => {
          const blob = new Blob([svg], { type: 'image/svg+xml' })
          const url = window.URL.createObjectURL(blob)
          const link = document.createElement('a')
          link.href = url
          link.download = 'process.svg'
          link.click()
          window.URL.revokeObjectURL(url)
          ElMessage.success('下载成功')
        })
      } catch (err) {
        ElMessage.error('下载失败')
      }
    },
    copyXML() {
      try {
        navigator.clipboard.writeText(this.xmlContent)
        ElMessage.success('复制成功')
      } catch (err) {
        ElMessage.error('复制失败')
      }
    },
    async deployModel() {
      this.fileNameDialogVisible = false
      let loading = null
      try {
        // 显示上传中提示
        loading = this.$loading({
          lock: true,
          text: '流程部署中...',
          spinner: 'el-icon-loading',
          background: 'rgba(0, 0, 0, 0.7)'
        })

        // 获取当前编辑器的 XML 内容
        const { xml } = await this.modeler.saveXML({ format: true })
        
        // 解析XML获取process name
        const parser = new DOMParser()
        const xmlDoc = parser.parseFromString(xml, 'text/xml')
        const processElement = xmlDoc.getElementsByTagName('bpmn:process')[0]
        const processName = processElement.getAttribute('name');
        const keyId = processElement.getAttribute("id")
        if (keyId == null || keyId == '') {
          this.$message.error('请先编辑流程标识')
          return
        }
        if(processName == null || processName == ''){
          this.$message.error('请先编辑流程名称')
          return
        }
        
        // 创建文件对象，使用process name作为文件名
        const file = new File(
          [new Blob([xml], { type: 'application/xml' })],
          `${processName}.bpmn20.xml`,
          { type: 'application/xml' }
        )
        
        
        // 创建 FormData 对象
        const formData = new FormData()
        formData.append('file', file)

        // 发送请求到后端
        const res = await this.$uploadFile('/deployFlowReal', formData.get('file'), onProgress => {
          if (loading) {
            loading.text = `部署中 ${onProgress}%`
          }
        })

        if (res.code == 200) {
          ElMessage.success(res.msg)
        } else {
          ElMessage.error(res.msg || '部署失败')
        }
      } catch (err) {
        console.error('流程部署失败:', err)
        ElMessage.error('流程部署失败')
      } finally {
        // 确保 loading 存在时才关闭
        if (loading) {
          loading.close()
        }
      }
    },
    saveAsTemplate() {
      // 显示文件名称输入对话框
      this.fileNameDialogVisible = true
    },
    async handleFileNameConfirm() {
      if (!this.fileNameForm.name) {
        ElMessage.warning('请输入文件名称')
        return
      }

      this.fileNameDialogVisible = false
      let loading = null
      try {
        // 显示上传中提示
        loading = this.$loading({
          lock: true,
          text: '保存模板中...',
          spinner: 'el-icon-loading',
          background: 'rgba(0, 0, 0, 0.7)'
        })

        // 获取当前编辑器的 XML 内容
        const { xml } = await this.modeler.saveXML({ format: true })
        
        // 创建文件对象，使用用户输入的文件名
        const file = new File(
          [new Blob([xml], { type: 'application/xml' })],
          `${this.fileNameForm.name}.bpmn20.xml`,
          { type: 'application/xml' }
        )
        
        // 创建 FormData 对象
        const formData = new FormData()
        formData.append('file', file)

        // 发送请求到后端
        const res = await this.$uploadFile('/uploadProcess', formData.get('file'), onProgress => {
          if (loading) {
            loading.text = `保存中 ${onProgress}%`
          }
        })

        if (res.code === 200) {
          ElMessage.success('模板保存成功')
          // 刷新模型列表
          await this.fetchList()
          // 清空文件名称
          this.fileNameForm.name = ''
        } else {
          ElMessage.error(res.msg || '保存失败')
        }
      } catch (err) {
        console.error('保存模板失败:', err)
        ElMessage.error('保存模板失败，请稍后重试')
      } finally {
        // 确保 loading 存在时才关闭
        if (loading) {
          loading.close()
        }
      }
    },
    closeEditor() {
      this.$router.push('/workflow/process-definition')
    },
    showMethods() {
      this.methodsDialogVisible = true
    },
    useMethod(method) {
      ElMessage.success(`已应用${method.name}方法`)
      this.methodsDialogVisible = false
    }
  }
}
</script>

<style scoped>
.process-editor-container {
  height: 100vh;
  display: flex;
  flex-direction: column;
}
.toolbar {
  padding: 8px;
  border-bottom: 1px solid #dcdfe6;
  display: flex;
  justify-content: space-between;
  background-color: #fff;
}
.left-tools,
.right-tools {
  display: flex;
  align-items: center;
}
.right-tools .el-button {
  display: flex;
  align-items: center;
  gap: 4px;
  border-radius: 0;
  margin-left: -1px;
}
.right-tools .el-button:first-child {
  border-radius: 4px 0 0 4px;
}
.right-tools .el-button:last-child {
  border-radius: 0 4px 4px 0;
}
.main-content {
  flex: 1;
  display: flex;
  overflow: hidden;
}
.bpmn-editor {
  flex: 1;
  height: 100%;
  background-color: #f5f7fa;
}
.properties-panel {
  width: 300px;
  border-left: 1px solid #dcdfe6;
  background-color: #fff;
  overflow-y: auto;
  padding: 0 !important;
}
.xml-content {
  background-color: #f5f7fa;
  padding: 16px;
  border-radius: 4px;
  max-height: 500px;
  overflow: auto;
  font-family: monospace;
}
.no-selection {
  color: #909399;
  text-align: center;
  padding: 20px;
}
:deep(.djs-label) {
  font-size: 14px;
  font-weight: bold;
  fill: #303133;
  pointer-events: none;
}
:deep(.djs-label text) {
  font-size: 14px;
  font-weight: bold;
  fill: #303133;
}
:deep(.djs-element) {
  fill-opacity: 1;
}
:deep(.djs-element .djs-label) {
  display: block !important;
  visibility: visible !important;
  opacity: 1 !important;
}
:deep(.djs-container) {
  height: 100%;
}
:deep(.djs-palette) {
    top: 0 !important;
    left: 0 !important;
    border-right: 1px solid #dcdfe6;
    box-sizing: border-box;
    width: 48px;
}
:deep(.djs-palette .djs-palette-toggle) {
    display: none !important;
}
</style>
